package com.mrx.compose.test.ui

import androidx.compose.foundation.LocalScrollbarStyle
import androidx.compose.foundation.clickable
import androidx.compose.foundation.defaultScrollbarStyle
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.DefaultComponentContext
import com.arkivanov.decompose.ExperimentalDecomposeApi
import com.arkivanov.decompose.extensions.compose.jetbrains.lifecycle.LifecycleController
import com.arkivanov.decompose.extensions.compose.jetbrains.stack.Children
import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.*
import com.arkivanov.decompose.router.stack.*
import com.arkivanov.essenty.lifecycle.LifecycleRegistry
import com.arkivanov.essenty.parcelable.Parcelable

object DeComposeWindow {


    private val localComponentContext: ProvidableCompositionLocal<ComponentContext> =
        staticCompositionLocalOf { error("Root component context was not provided") }

    @Composable
    fun provideComponentContext(componentContext: ComponentContext, content: @Composable () -> Unit) {
        CompositionLocalProvider(localComponentContext provides componentContext, content = content)
    }

    @JvmStatic
    @OptIn(ExperimentalDecomposeApi::class)
    fun main(args: Array<String>) {
        val lifecycle = LifecycleRegistry()
        val rootComponentContext = DefaultComponentContext(lifecycle)
        application {
            val windowState = rememberWindowState().apply {
                size = DpSize(600.dp, 800.dp)
                position = WindowPosition(Alignment.Center)
            }
            LifecycleController(lifecycle, windowState)
            Window(
                onCloseRequest = ::exitApplication,
                state = windowState,
                title = "Compose Navigator Example"
            ) {
                Surface(modifier = Modifier.fillMaxSize()) {
                    MaterialTheme {
                        CompositionLocalProvider(LocalScrollbarStyle provides defaultScrollbarStyle()) {
                            provideComponentContext(rootComponentContext) {
                                mainContent()
                            }
                        }
                    }
                }
            }
        }
    }

    @Composable
    fun mainContent() {
        val navigation = remember { StackNavigation<Screen>() }
        childStack(
            source = navigation,
            initialStack = { listOf(Screen.List) },
            handleBackButton = true,
            animation = stackAnimation(fade() + scale()),
        ) { screen ->
            when (screen) {
                is Screen.List -> Screen.List.listContent {
                    navigation.push(Screen.Details(it))
                }

                is Screen.Details -> Screen.Details.detailsContent(screen.text) {
                    navigation.pop()
                }
            }
        }
    }

    private sealed class Screen : Parcelable {
        object List : Screen() {

            @Composable
            fun listContent(onItemClick: (String) -> Unit) {
                val itemList = remember { List(100) { "Item $it" } }
                LazyColumn {
                    items(itemList.size) { item ->
                        val itemText = itemList[item]
                        Text(
                            text = itemText,
                            modifier = Modifier
                                .clickable { onItemClick(itemText) }
                                .fillMaxWidth()
                                .padding(16.dp)
                        )
                    }
                }
            }

        }

        data class Details(val text: String) : Screen() {

            companion object {
                @Composable
                fun detailsContent(text: String, onBack: () -> Unit) {
                    Column(modifier = Modifier.padding(16.dp)) {
                        Text(text)

                        Spacer(modifier = Modifier.height(16.dp))

                        Button(onClick = onBack) {
                            Text(text = "Back")
                        }
                    }
                }
            }
        }
    }

    @Composable
    private inline fun <reified C : Parcelable> childStack(
        source: StackNavigationSource<C>,
        noinline initialStack: () -> List<C>,
        modifier: Modifier = Modifier,
        handleBackButton: Boolean = false,
        animation: StackAnimation<C, ComponentContext>? = null,
        noinline content: @Composable (C) -> Unit,
    ) {
        val componentContext = localComponentContext.current
        Children(
            stack = remember {
                componentContext.childStack(
                    source = source,
                    initialStack = initialStack,
                    handleBackButton = handleBackButton,
                    childFactory = { _, childComponentContext -> childComponentContext },
                )
            },
            modifier = modifier,
            animation = animation,
        ) { child ->
            provideComponentContext(child.instance) {
                content(child.configuration)
            }
        }
    }

}
